﻿///-----------------
///资源管理器
///-----------------

using System;
using System.Collections.Generic;
using Object = UnityEngine.Object;

namespace FrameWorkSong
{
    internal class ResLoader
    {
        #region public
        /// <summary>
        /// 同步加载assetBundle资产
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="assetBundleName"></param>
        /// <param name="assetName"></param>
        /// <param name="assetPath">assetBundle路径</param>
        /// <returns></returns>
        public T LoadAssetSync<T>(string assetBundleName, string assetName, string assetBundlePath) where T : Object
        {
            return DoLoadAssetSync<T>(assetName, assetBundlePath, assetBundleName);
        }
        /// <summary>
        /// 同步加载资产
        /// </summary>
        /// <typeparam name="T">资产类型</typeparam>
        /// <param name="assetName">资产名称</param>
        /// <param name="assetPath">资产路径</param>
        /// <returns></returns>
        public T LoadAssetSync<T>(string assetName, string assetPath) where T : Object
        {
            return DoLoadAssetSync<T>(assetName, assetPath);
        }
        /// <summary>
        /// 异步加载assetBundle资产
        /// </summary>
        /// <typeparam name="T">资产类型</typeparam>
        /// <param name="assetBundleName">assetBundle名称</param>
        /// <param name="assetName">资产名称</param>
        /// <param name="assetBundlePath">assetBundle路径</param>
        /// <param name="onLoaded">资产名称</param>
        public void LoadAssetAsync<T>(string assetBundleName, string assetName, string assetBundlePath, Action<T> onLoaded) where T : Object
        {
            DoLoadAssetAsync<T>(assetName, assetBundlePath, onLoaded, assetBundleName);
        }
        /// <summary>
        /// 异步加载资产
        /// </summary>
        /// <typeparam name="T">资产类型</typeparam>
        /// <param name="assetName">资产名称</param>
        /// <param name="assetPath">资产路径</param>
        /// <param name="onLoaded">资产名称</param>
        public void LoadAssetAsync<T>(string assetName, string assetPath, Action<T> onLoaded) where T : Object
        {
            DoLoadAssetAsync<T>(assetName, assetPath, onLoaded);
        }
        /// <summary>
        /// 清理资产
        /// </summary>
        /// <param name="AssetName">资产名称</param>
        public void Release(string AssetName)
        {
            var res = my_ResRecord.Find(loadedAsset => loadedAsset.Name == AssetName);
            if (res != null)
            {
                res.Release();
                my_ResRecord.Remove(res);
            }
            if (my_ResRecord.Count == 0)
            {
                my_ResRecord.Clear();
            }
        }
        /// <summary>
        /// 销毁所有资产
        /// </summary>
        public void ReleaseAll()
        {
            if (my_ResRecord != null)
            {
                my_ResRecord.ForEach(loadedAsset => loadedAsset.Release());
                my_ResRecord.Clear();
                // my_ResRecord = null;
            }
        }
        /// <summary>
        /// 销毁所有记录
        /// </summary>
        public void ReleaseAllRecord()
        {
            my_ResRecord.Clear();
        }
        #endregion

        #region private
        /// <summary>
        /// 同步加载资源
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="assetName"></param>
        /// <param name="assetPath"></param>
        /// <param name="assetBundleName"></param>
        /// <returns></returns>
        T DoLoadAssetSync<T>(string assetName, string assetPath, string assetBundleName = null) where T : Object
        {
            var res = GetOrCreateRes(assetName);
            if (res != null)
            {
                switch (res.State)
                {
                    case ResState.Loading:
                        throw new System.Exception(string.Format("请不要在异步加载资源{0}时，同步加载{0}", assetName));
                    case ResState.Loaded:
                        return res.Asset as T;
                }
            }
            res = CreateRes(assetName, assetPath, assetBundleName);
            res.LoadAssetSync();
            return res.Asset as T;
        }
        /// <summary>
        /// 异步加载资源
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="assetName"></param>
        /// <param name="assetPath"></param>
        /// <param name="onLoaded"></param>
        /// <param name="assetBundleName"></param>
        void DoLoadAssetAsync<T>(string assetName, string assetPath, Action<T> onLoaded, string assetBundleName = null) where T : Object
        {
            var res = GetOrCreateRes(assetName);
            Action<Res> onResLoaded = null;
            //给onResLoaded赋值
            onResLoaded = loadedRes =>
            {
                //当加载完成后，my_OnLoadedEvent事件调用onLoaded方法
                onLoaded(loadedRes.Asset as T);
                // 注销onResLoaded方法
                res.UnRegisterOnLoadedEvent(onResLoaded);
            };
            if (res != null)
            {
                if (res.State == ResState.Loading)
                {
                    //当正在加载时，注册onResLoaded方法
                    res.RegisterOnLoadedEvent(onResLoaded);
                }
                else if (res.State == ResState.Loaded)
                {
                    onLoaded(res.Asset as T);
                }
                return;
            }
            res = CreateRes(assetName, assetPath, assetBundleName);
            res.RegisterOnLoadedEvent(onResLoaded);
            res.LoadAssetAsync();
        }
        /// <summary>
        /// 查询当前的资源记录得到资源
        /// </summary>
        /// <param name="assetName">资产名称</param>
        /// <returns></returns>
        private Res GetResFromRecord(string assetName)
        {
            return my_ResRecord.Find(loadedAsset => loadedAsset.Name == assetName);
        }
        /// <summary>
        /// 查询全局的资源记录得到资源
        /// </summary>
        /// <param name="assetName">资产名称</param>
        /// <returns></returns>
        private Res GetResFromMgr(string assetName)
        {
            return ResMgr.Instance.ShareLoadedAssets.Find(loadedAsset => loadedAsset.Name == assetName);
        }
        /// <summary>
        /// 资源记录到本地
        /// </summary>
        /// <param name="res"></param>
        private void AddResToRecord(Res res)
        {
            my_ResRecord.Add(res);
            res.Retain();
        }
        /// <summary>
        /// 创建资源
        /// </summary>
        /// <param name="assetName">资产名称</param>
        /// <param name="assetPath">资产路径</param>
        /// <param name="ownerBundel">Bundel名称</param>
        /// <returns></returns>
        private Res CreateRes(string assetName, string assetPath, string ownerBundel = null)
        {
            Res res = ResFactory.Create(assetName, assetPath, ownerBundel);
            AddResToRecord(res);
            ResMgr.Instance.ShareLoadedAssets.Add(res);
            return res;
        }
        /// <summary>
        /// 得到或者创建资源判断
        /// </summary>
        /// <param name="assetName">资产名称</param>
        /// <returns></returns>
        private Res GetOrCreateRes(string assetName)
        {
            //查询当前的资源记录
            var res = GetResFromRecord(assetName);
            if (res != null)
            {
                return res;
            }
            //查询全局的资源记录
            res = GetResFromMgr(assetName);
            if (res != null)
            {
                AddResToRecord(res);
                return res;
            }
            return res;
        }
        /// <summary>
        /// 本地资源记录
        /// </summary>
        private List<Res> my_ResRecord = new List<Res>();
        #endregion
    }
}
